package com.lavender.chapter1_introduction;

import java.util.concurrent.atomic.AtomicBoolean;

/**
 * <p>练习题一：五个哲学家进餐问题</p>
 *
 * @author lavender
 * @since 2018/11/11 20:33
 */
public class Exercise1 {

    /**
     * 第一小题：模拟哲学家进餐. 每个哲学家是一个线程, 筷子是共享对象.
     * Note: 不能存在两个哲学家同时拥有同一支筷子的情况
     *
     * 第二小题：改进程序防止死锁
     */
    static class Question1And2 {
        // 用AtomicBoolean值表示筷子, True表示获得筷子
        AtomicBoolean[] chopsticks = new AtomicBoolean[]{
                new AtomicBoolean(false),
                new AtomicBoolean(false),
                new AtomicBoolean(false),
                new AtomicBoolean(false),
                new AtomicBoolean(false)
        };

        void simulate() {
            int len = chopsticks.length;
            for (int i = 0; i < len; i++) {
                new Thread(new Philosopher(chopsticks[i % len], chopsticks[(i + 1) % len])).start();
            }
        }

        /**
         * 哲学家类
         */
        private static class Philosopher implements Runnable {
            private AtomicBoolean leftChopstick;
            private AtomicBoolean rightChopstick;

            Philosopher(AtomicBoolean leftChopstick, AtomicBoolean rightChopstick) {
                this.leftChopstick = leftChopstick;
                this.rightChopstick = rightChopstick;
            }

            /**
             * 很显然会造成饥饿, 不能保证任意一个哲学家一定可以获得两支筷子
             */
            @Override
            public void run() {
                for (; ; ) {
                    if (leftChopstick.compareAndSet(false, true)) {
                        if (rightChopstick.compareAndSet(false, true)) {
                            simulateEating();
                            // 退出
                            leftChopstick.set(false);
                            rightChopstick.set(false);
                        } else {
                            rightChopstick.set(false);
                        }
                    } else {
                        leftChopstick.set(false);
                    }
                }
            }

            private void simulateEating() {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    // no op
                }
            }
        }
    }

    /**
     * 第三小题：改进程序防止饥饿发生
     */
    static class Question3 {
        // 防止饥饿意味着需要提供先来先得的服务, 然而我们的问题是五个线程
        // 请求的共享对象并不是简单的单个对象

    }

    /**
     * 第四小题：为任意数量的哲学家们提供Starvation-free的解决方案
     */

}
